#pragma once
#include "tcpServer.hpp"
#define NUM (sizeof(fd_set)*8)
#define DFL -1

class SelectServer
{
    public:
      SelectServer(int port= 8080)
        :_port(port)
      {
          for(int i=0; i < static_cast<int>NUM; i++) _rfd_array[i] = _wfd_array[i] = DFL;
      }
      void SelectServerInit()
      {
        try{
             _lsock = TcpServer::Socket();
             TcpServer::Bind(_lsock,_port);
             TcpServer::Listen(_lsock);
             _rfd_array[0] = _lsock;
             cout<<"_lsock"<<_lsock<<endl;
        }  
        catch(exception& e)
        {
            cout<<"SelectServerInit"<<" "<<e.what()<<endl;
        }
      }
      void SelectServerStart()
      {
        while(1)
        {
          int nfds = 0;
          /*由于输入型和输出型参数合二为一,要每次进行select的*readfds和*writefds的重新绑定以及新文件描述符的绑定*/
          fd_set rfds,wfds;
          FD_ZERO(&rfds);FD_ZERO(&wfds);
          for(int i = 0 ; i < static_cast<int>NUM; i++)
          {
              if( _rfd_array[i] != DFL )
              {
                 FD_SET(_rfd_array[i],&rfds);
                 nfds = max(nfds, _rfd_array[i]);
              }
              if( _wfd_array[i] != DFL )
              {
                 FD_SET(_wfd_array[i],&wfds);
                 nfds = max(nfds,_wfd_array[i]);
              }
          }
          struct timeval timeout;
          timeout.tv_sec = 10;
          timeout.tv_usec = 0;
          cout<<"nfds="<<nfds<<endl; 
          cout<<endl;
          cout<<"select begin..."<<endl;
          switch(select(nfds+1,&rfds,&wfds,nullptr,&timeout))
          {
             case 0:
               cout<<" timeout..." << endl;
               break;
             case -1:
               cerr<<"select error..."<<endl;
               break;
             default:
               cout<<"Rervice()"<<endl;
               Rervice(&rfds , &wfds);
               break;
          }
        }
      }
      void Rervice( fd_set* rfds , fd_set* wfds )
      {
           for(int i =0 ; i < static_cast<int>NUM ; i++ )
           {
              if( _rfd_array[i] == DFL ) continue;
              if( FD_ISSET ( _rfd_array[i] , rfds ) )
              {
                  if( _rfd_array[i] == _lsock )
                  {
                      int sock = TcpServer::Accept(_lsock);
                      if( sock >=0 )
                      {
                          cout<<"get a new link..."<<endl;
                      }
                      Add2ReadFD(sock);
                  }
                  else//给读使用的,此时数据已经就绪不会发生阻塞,直接进行拷贝,要考虑到recv收到的字节数符合应用层协议
                  {
                      //考虑应用层协议的在epoll的demo中实现
                      char buf[10240];
                      //bug!
                      int recnum = recv(_rfd_array[i] , buf , (int)sizeof(buf)-1 , 0 );
                      
                      if(recnum > 0)
                      {
                          cout<<"echo #:receive "<<recnum<<"bytes   :"<< buf << endl;
                      }
                      else if( recnum == 0 )
                      {
                          cout<<"client quit..."<<endl;
                      }
                      Add2WriteFD(_rfd_array[i]);//修改为写事件
                      DelFromReadFD(i);
                  }
              }
              else if( FD_ISSET(_wfd_array[i],wfds) )
              {
                    char buf[10240] = {" I am received . connect is over . good bye\n"};
                    send(_wfd_array[i] , buf, sizeof(buf) , 0);
                    close(_wfd_array[i]);
                    DelFromWriteFD(i);
              }
           }
      }
      void Add2ReadFD(int fd)
      {
           int i = 0;
           for( ; i < static_cast<int>NUM ; i++)
           {
             if( _rfd_array[i] == DFL){
                 break;
             }
           }
           if( i >= static_cast<int>NUM )
           {
              cerr <<"fd array is full"<<endl;
              close(fd);
           }
           else{
              _rfd_array[i] = fd; 
              cout<<"readfd :"<<fd<<endl;
           }
      }
      void Add2WriteFD(int fd)
      {
            int i = 0;
            for( ; i< static_cast<int>NUM ; i++ )
            {
                if( _wfd_array[i] == DFL )
                {
                    break; 
                }
            }
            if( i>= static_cast<int> NUM )
            {
                cout<<"_wfd_array is full ..."<<endl;
                close(fd);
            }
            else{
               _wfd_array[i] = fd;
               cout<<"writefd :"<<fd<<endl;
            } 
      }
      void DelFromReadFD(int idx)
      {
           if( idx >=0 && idx < static_cast<int>NUM ) _rfd_array[idx] = DFL; 
      }
      void DelFromWriteFD(int idx)
      {
           if( idx >=0 && idx < static_cast<int>NUM ) _wfd_array[idx] = DFL;
      }
      ~SelectServer()
      {}
    private:
      int _lsock;
      int _port;
      int _rfd_array[NUM];
      int _wfd_array[NUM];
};
